__author__ = "Daniel Rothenberg"
__version__ = "0.1"

'''Quizzy - the Quiz Bowl moderating robot.

Quizzy will pull questions from Carlo Anguili's ACF database
and read them to the collaborators in a wave. It will then listen
'buzzes' and determine whether a given answer is correct.
'''

from waveapi import events
from waveapi import model
from waveapi import robot
from waveapi import document

from google.appengine.ext import db
from question import Question
import random, time, re 

CMD_HELP = 'quizzy:help'

QUESTION_IN_PROGRESS = False
DB_QUESTIONS = 12286

LEVELS = ['fall', 'winter', 'regionals', 'nationals']
GEN_CATEGORIES = ['fine arts', 'history', 'literature', 'other',
                  'science', 'social studies']

STR_USAGE = '''
    
    Here are some commands you can use to let me know what types of questions I should serve you:

    [random] - A totally random question from the acfdb.
    [<level>, <category>] - Specify a specific combination of levels and general categories.
        
        Possible values for levels and categories:
                Levels = %s
                Categories = %s
                
            - alternatively, use the keyword 'random' in either place to indicate no preference.
            
    Enjoy!
    ''' % (LEVELS, GEN_CATEGORIES)
    
class KeywordError(Exception):
    '''Error to raise when an unknown category or level is passed by user
    
    Arguments:
        keyword - the anomalous strong
        type - a string, either 'category' or 'level'
    '''
    def __init__(self, keyword, type):
        self.keyword = keyword
        self.type = type
    
def OnRobotAdded(properties, context):
    """Invoked when the robot has been added."""
    Notify(context, "Hey there, I'm a designated Quiz Bowl question reader!\n"+STR_USAGE)
    
def Notify(context, message):
    root_wavelet = context.GetRootWavelet()
    root_wavelet.CreateBlip().GetDocument().SetText(message)
    
def OnBlipSubmit(properties, context):
    """Invoked when new blip submitted. Search for commands."""
    blip = context.GetBlipById(properties['blipId'])
    doc = blip.GetDocument()
    text = doc.GetText()
    newDoc = None
    
    if CMD_HELP in text:
        newBlip = blip.CreateChild()
        newDoc = newBlip.GetDocument()
        newDoc.SetText(STR_USAGE)
    elif "[random]" in text:
        AskQuestion(blip, context)    
    else:
        random_pattern = re.compile(r'\[(?P<level>\w+), (?P<category>[\w\s]+)\]')
        match = re.search(random_pattern, text)
        if  match != None:
            ## Prepare the match to send to AskQuestion()
            ##   - we need to ensure that everything is lowercase,
            ##   and that we know how to handle the data            
            matchDict = match.groupdict()
            level, category = None, None
            try:
                level, category = AffirmKeywords(matchDict['level'], matchDict['category'])
            except KeywordError, e:
                errorBlip = blip.GetDocument().AppendInlineBlip()
                errorDoc = errorBlip.GetDocument()
                errorDoc.SetText("\nI'm sorry, I don't understand the %s keyword '%s'"
                                 % (e.type, e.keyword))
                return                
            AskQuestion(blip, context, category=category, level=level)
            
def AffirmKeywords(level, category):
    if not (level in LEVELS or level == 'random'):
        raise KeywordError(level, 'level')
    if not (category in GEN_CATEGORIES or category == 'random'):
        raise KeywordError(category, 'category')
    return level, category    

def AskQuestion(blip, context, category=None, level=None):
    newBlip = blip.CreateChild()
    newDoc = newBlip.GetDocument()
    
    category = None if (category == 'random') else category
    level = None if (level == 'random') else level
    
    if (category == None and level == None):
        n = random.choice(range(1, DB_QUESTIONS+1))
        q = db.GqlQuery("SELECT * FROM Question WHERE id = %d" % n)
        question = q.fetch(1)[0]
        
    else:
        q = Question.all()
        if category in GEN_CATEGORIES:
            fixed_cats = {'fine arts':'Fine Arts', 'history':'History', 'literature':'Literature', 'other':'Other',
                          'science':'Science', 'social studies':'Social Studies'}
            q.filter("gen_category =", fixed_cats[category])
        if level in LEVELS: q.filter("level =", level)
        
        questions = q.fetch(500)
        n = random.choice(range(len(questions)))
        question = questions[n]
        
    question_text = question.question
    question_answer = question.answer        
    text_bits = question_text.split()
    
    newDoc.SetText("\n"+question_text+"\n")
    
    #for word in text_bits:
    #    doc_text = newDoc.GetText()
    #    newDoc.AppendText(" %s" % word)
    #    #time.sleep(.1)
    
    answer_blip = newDoc.AppendInlineBlip()
    answer_blip_id = answer_blip.GetId()
    answer_doc = answer_blip.GetDocument()
    answer_doc.SetText('\nAnswer: '+question_answer)
    
if __name__ == '__main__':

    myRobot = robot.Robot('Quizzy',
        image_url = 'http://quizzy-robot.appspot.com/images/quizzy_logo.png',
        version = '1',
        profile_url = 'http://code.google.com/p/quizzy/')
    myRobot.RegisterHandler(events.WAVELET_SELF_ADDED, OnRobotAdded)
    myRobot.RegisterHandler(events.BLIP_SUBMITTED, OnBlipSubmit)
    myRobot.Run()